home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / plan / src / weekdraw.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  15KB  |  506 lines

  1. /*
  2.  * week menu widgets.
  3.  *
  4.  *    clicked_week_calendar(x, y)    Press on the week display detected.
  5.  *    draw_week_day(day, month, year)    The day day/month/year has changed,
  6.  *                    redraw the week view if it contains
  7.  *                    that day.
  8.  *    draw_week_calendar()        If there is a week menu, resize, and
  9.  *                    redraw
  10.  *    redraw_week_calendar()        Same, but assume that it's still the
  11.  *                    same week, so don't recalc and resize.
  12.  */
  13.  
  14. #include <time.h>
  15. #include <Xm/Xm.h>
  16. #include "cal.h"
  17.  
  18. #define DBLTIME        1000        /* doubleclick time [ms] */
  19.  
  20. #define SLOPE        1/4        /* slope of arrow head / barheight */
  21. #define MINLEN        8        /* no bar is shorter than MINLEN */
  22.  
  23. #define TOD(t)        ((t)%86400)
  24. #define BOUND(t,a,b)    ((t)<(a) ? (a) : (t)>(b) ? (b) : (t));
  25. #define XPOS(t)        (((t) - c->week_minhour*3600) * c->week_hourwidth/3600)
  26.  
  27.  
  28. extern char *mktimestring(), *mkdatestring();
  29. extern char *parse_holidays();
  30. extern struct tm *time_to_tm();
  31. extern time_t tm_to_time();
  32. static draw_week_day_background();
  33. static draw_week_day_foreground();
  34. static draw_bar();
  35.  
  36. extern Display        *display;    /* everybody uses the same server */
  37. extern GC        jgc, gc;    /* graphic context, Japanese and std */
  38. extern XFontStruct    *font[NFONTS];    /* fonts: FONT_* */
  39. extern struct config    config;        /* global configuration data */
  40. extern struct mainmenu    mainmenu;    /* all important main window widgets */
  41. extern time_t        curr_week;    /* week being displayed, time in sec */
  42. extern struct week    week;        /* info on week view */
  43. extern struct list    *mainlist;    /* list of all schedule entries */
  44. extern struct holiday    holiday[366];    /* info for each day, separate for */
  45. extern struct holiday    sm_holiday[366];/* full-line texts under, and small */
  46.  
  47. extern char *weekday_name[];
  48. extern char *monthname[];
  49.  
  50.  
  51. /*
  52.  * got a click in the calendar area. Traverse the node tree, first down until
  53.  * the correct line is found, and then horizontally until the node is found.
  54.  */
  55.  
  56. clicked_week_calendar(xc, yc, time)
  57.     int            xc, yc;        /* pixel pos clicked */
  58.     Time            time;        /* current time in ms */
  59. {
  60.     register struct config    *c = &config;
  61.     struct weeknode        *vert, *horz;    /* week node scan pointers */
  62.     register struct entry    *ep;        /* entry to test */
  63.     static struct entry    *last_ep;    /* last entry found (dblclk?)*/
  64.     static Time        last_time;    /* time of last press */
  65.     int            d;        /* day counter */
  66.     int            yd;        /* y start coord of day box */
  67.     int            x, y;        /* upper left of day bk box */
  68.     int            ys;        /* height of bar line w/ gaps*/
  69.     time_t            btime;        /* start time of bar */
  70.     int            b, e;        /* X start end end pos of bar*/
  71.     int            xend;        /* right margin of chart */
  72.  
  73.     x  = c->week_margin + c->week_daywidth + c->week_gap;
  74.     yd = 2*c->week_margin + c->week_title + c->week_hour + c->week_gap + 2;
  75.     ys = c->week_barheight + 2*c->week_bargap;
  76.     xend = x + c->week_hourwidth * (c->week_maxhour - c->week_minhour);
  77.  
  78.     for (d=0; d < NDAYS; d++) {
  79.         for (y=yd, vert=week.tree[d]; vert; vert=vert->down, y+=ys) {
  80.         if (yc < y || yc >= y+ys)
  81.             continue;
  82.         if (xc < x) {
  83.             create_list_popup(mainlist, curr_week + d*86400,
  84.                                 86400, 0, 0);
  85.             return;
  86.         }
  87.         for (horz=vert; horz; horz=horz->next) {
  88.             draw_bar(horz, horz->user ? horz->user->color : 0,
  89.                             x, y + c->week_bargap);
  90.  
  91.             ep = horz->entry;
  92.             btime = TOD(ep->time);
  93.             if (config.weekwarn)
  94.                 btime -= ep->early_warn > ep->late_warn
  95.                         ? ep->early_warn
  96.                         : ep->late_warn;
  97.             if (btime < c->week_minhour*3600)
  98.                 btime = c->week_minhour*3600;
  99.             e = b = x + XPOS(TOD(btime));
  100.             if (!ep->notime)
  101.                 e += ep->length * c->week_hourwidth/3600;
  102.             if (e < b + MINLEN)
  103.                 e = b + MINLEN;
  104.             if (!horz->textinside)
  105.                 e += horz->textlen;
  106.             if (xc >= b && xc < e ||
  107.                 xc >= xend-MINLEN && b >= xend) {
  108.                 if (time-last_time < DBLTIME && ep == last_ep){
  109.                     if (horz->user)
  110.                         print_button(week.info,
  111.                                 "cannot edit");
  112.                     else
  113.                         create_list_popup(mainlist,
  114.                                 0, 0, 0, ep);
  115.                     last_ep = 0;
  116.                     return;
  117.                 } else if (horz->user)
  118.                     print_button(week.info, "%s (%s) %s",
  119.                         mktimestring(ep->time, FALSE),
  120.                         horz->user->name,
  121.                         ep->note ? ep->note : "");
  122.                 else
  123.                     print_button(week.info, "%s %s",
  124.                         mktimestring(ep->time, FALSE),
  125.                         ep->note ? ep->note : "");
  126.                 last_ep   = ep;
  127.                 last_time = time;
  128.                 return;
  129.             }
  130.         }
  131.         }
  132.         yd += week.nlines[d] * ys + c->week_gap;
  133.     }
  134.     print_button(week.info, " ");
  135. }
  136.  
  137.  
  138. /*
  139.  * If the specified date is in the current week, redraw everything (something
  140.  * changed on the specified day).
  141.  */
  142.  
  143. draw_week_day(day, month, year)
  144.     int        day, month, year;
  145. {
  146.     struct tm    tm;
  147.     time_t        date;
  148.  
  149.     tm.tm_year = year;
  150.     tm.tm_mon  = month;
  151.     tm.tm_mday = day;
  152.     tm.tm_hour = 0;
  153.     tm.tm_min  = 0;
  154.     tm.tm_sec  = 0;
  155.     date = tm_to_time(&tm);
  156.     if (date >= curr_week && date < curr_week * NDAYS*86400) {
  157.         build_week();
  158.         draw_week_calendar();
  159.     }
  160. }
  161.  
  162.  
  163. /*
  164.  * draw the entire week menu, unconditionally. Calling create_week_menu
  165.  * will cause a callback to redraw_week_calendar, either explicitly or
  166.  * because of an expose event.
  167.  */
  168.  
  169. draw_week_calendar()
  170. {
  171.     if (!week.canvas)
  172.         return;
  173.     create_week_menu();            /* recalc & resize */
  174. }
  175.  
  176.  
  177. redraw_week_calendar()
  178. {
  179.     register struct config    *c = &config;
  180.     Window            window;
  181.     char            buf[40], *p;
  182.     XRectangle        rects[25+2];
  183.     int            i, l, x, y;
  184.  
  185.     if (!week.canvas)
  186.         return;
  187.     window = XtWindow(week.canvas);
  188.                             /* background */
  189.     set_color(COL_WBACK);
  190.     XFillRectangle(display, window, gc, 0, 0, week.canvas_xs,
  191.                           week.canvas_ys);
  192.  
  193.     strcpy(buf, mkdatestring(curr_week));        /* centered title */
  194.     strcat(buf, " - ");
  195.     strcat(buf, mkdatestring(curr_week + (NDAYS-1)*86400));
  196.     set_color(COL_WTITLE);
  197.     XSetFont(display, gc, font[FONT_WTITLE]->fid);
  198.     XDrawString(display, window, gc,
  199.             (week.canvas_xs - strlen_in_pixels(buf,FONT_WTITLE))/2, 
  200.             c->week_margin + c->week_title * 3/4,
  201.             buf, strlen(buf));
  202.  
  203.     for (i=0; i < NDAYS; i++)            /* day background */
  204.         draw_week_day_background(i);
  205.                             /* thick lines */
  206.     rects[0].x    = c->week_margin;
  207.     rects[0].y    = 2*c->week_margin + c->week_title + c->week_hour + 1;
  208.     rects[0].width  = week.canvas_xs - 2*c->week_margin +1;
  209.     rects[0].height = 2;
  210.     rects[1].x    = c->week_margin;
  211.     rects[1].y    = week.canvas_ys - c->week_margin +2;
  212.     rects[1].width  = week.canvas_xs - 2*c->week_margin +1;
  213.     rects[1].height = 2;
  214.                             /* thin lines */
  215.     x = c->week_margin + c->week_daywidth + c->week_gap;
  216.     y = 2*c->week_margin + c->week_title + c->week_hour + 3;
  217.     for (i=0; i <= c->week_maxhour-c->week_minhour; i++) {
  218.         rects[i+2].x      = x + i * c->week_hourwidth;
  219.         rects[i+2].y      = y;
  220.         rects[i+2].width  = 1;
  221.         rects[i+2].height = week.canvas_ys - c->week_margin -
  222.                             rects[i+2].y + 3;
  223.     }
  224.     set_color(COL_WGRID);
  225.     XFillRectangles(display, window, gc, rects, i+2);
  226.  
  227.     for (i=0; i < NDAYS; i++)            /* day foreground */
  228.         draw_week_day_foreground(i);
  229.                             /* hour labels */
  230.     set_color(COL_WDAY);
  231.     XSetFont(display, gc, font[FONT_WHOUR]->fid);
  232.     for (i=0; i <= c->week_maxhour-c->week_minhour; i++) {
  233.         p = mktimestring((i + c->week_minhour) * 3600, FALSE);
  234.         l = strlen_in_pixels(p, FONT_WHOUR);
  235.         XDrawString(display, window, gc,
  236.             x + i * c->week_hourwidth - l/2,
  237.             2*c->week_margin + c->week_title + c->week_hour -2,
  238.             p, strlen(p));
  239.     }
  240.     set_color(COL_STD);
  241. }
  242.  
  243.  
  244. /*
  245.  * draw the background of one day of the week at its position. This includes
  246.  * the day number and the box, but not the bars themselves. The bars are
  247.  * printed after the thin hour lines are drawn by the caller, by calling the
  248.  * following routine.
  249.  */
  250.  
  251. static draw_week_day_background(wday)
  252.     int            wday;        /* day of the week, < NDAYS */
  253. {
  254.     Window            window = XtWindow(week.canvas);
  255.     register struct config    *c = &config;
  256.     time_t            today;        /* today's date */
  257.     struct holiday        *hp, *shp;    /* to check for holidays */
  258.     char            *errmsg;    /* holiday parser error */
  259.     char            buf[20];    /* holiday text buffer */
  260.     struct tm        *tm;        /* today's date as m/d/y */
  261.     char            *p;        /* temp for day name */
  262.     int            x, y;        /* upper left of day bk box */
  263.     int            ys;        /* height of bar line w/ gaps*/
  264.     int            yt;        /* text y position */
  265.     int            yts;        /* vert space for text */
  266.     int            i;
  267.  
  268.     if (week.nlines[wday] == 0)
  269.         return;
  270.     x  = c->week_margin + c->week_daywidth + c->week_gap;
  271.     y  = 2*c->week_margin + c->week_title + c->week_hour + c->week_gap + 2;
  272.     ys = c->week_barheight + 2*c->week_bargap;
  273.     for (i=0; i < wday; i++)
  274.         y += week.nlines[i] * ys + c->week_gap;
  275.  
  276.                             /* clear weekday name*/
  277.     yts = week.nlines[wday] * ys + c->week_gap -1;
  278.     today = get_time() - (curr_week + wday*86400);
  279.     set_color(today < 0 || today >= 86400 ? COL_WBACK : COL_CALTODAY);
  280.     XFillRectangle(display, window, gc, c->week_margin, y,
  281.                     c->week_daywidth, yts);
  282.  
  283.                             /* weekday name */
  284.     yt = y + font[FONT_WDAY]->max_bounds.ascent;
  285.     i = (wday + 7 - c->sunday_first) % 7;
  286.     set_color(COL_WDAY);
  287.     XSetFont(display, gc, font[FONT_WDAY]->fid);
  288.     p = mkdatestring(curr_week + wday * 86400);
  289.     truncate_string(p, c->week_daywidth-2, FONT_WDAY);
  290.     XDrawString(display, window, gc, c->week_margin, yt, p, strlen(p));
  291.     yt += font[FONT_WDAY]->max_bounds.ascent +
  292.           font[FONT_WDAY]->max_bounds.descent;
  293.                             /* holidays */
  294.     tm = time_to_tm(curr_week + wday*86400);
  295.     if (errmsg = parse_holidays(tm->tm_year, FALSE))
  296.         create_error_popup(mainmenu.cal, 0, errmsg);
  297.     shp = &sm_holiday[tm->tm_yday];
  298.     hp  =    &holiday[tm->tm_yday];
  299.     for (i=0; i < 2; i++, shp=hp)
  300.         if (shp->string && yt < y + yts) {
  301.             strncpy(buf, shp->string, sizeof(buf)-1);
  302.             truncate_string(buf, c->week_daywidth-2, FONT_WDAY);
  303.             set_color(shp->stringcolor ? shp->stringcolor :
  304.                   shp->daycolor    ? shp->daycolor
  305.                            : COL_WDAY);
  306.             XDrawString(display, window, gc,
  307.                     c->week_margin + c->week_daywidth-2 -
  308.                     strlen_in_pixels(buf, FONT_WDAY),
  309.                     yt, buf, strlen(buf));
  310.             yt += font[FONT_WDAY]->max_bounds.ascent +
  311.                   font[FONT_WDAY]->max_bounds.descent;
  312.         }
  313.                             /* appointment box */
  314.     set_color(COL_WBOXBACK);
  315.     XFillRectangle(display, window, gc, x, y,
  316.                     week.canvas_xs - c->week_margin - x,
  317.                     week.nlines[wday] * ys);
  318. }
  319.  
  320.  
  321. /*
  322.  * draw the foreground of one day of the week at its position. This includes
  323.  * all the bars. The background and the thin vertical lines have already been
  324.  * drawn by the caller.
  325.  */
  326.  
  327. static draw_week_day_foreground(wday)
  328.     int            wday;        /* day of the week, < NDAYS */
  329. {
  330.     register struct config    *c = &config;
  331.     struct weeknode        *vert, *horz;    /* week node scan pointers */
  332.     int            x, y;        /* upper left of day bk box */
  333.     int            ys;        /* height of bar line w/ gaps*/
  334.     int            i;
  335.  
  336.     x  = c->week_margin + c->week_daywidth + c->week_gap;
  337.     y  = 2*c->week_margin + c->week_title + c->week_hour + c->week_gap + 2;
  338.     ys = c->week_barheight + 2*c->week_bargap;
  339.     for (i=0; i < wday; i++)
  340.         y += week.nlines[i] * ys + c->week_gap;
  341.  
  342.     for (vert=week.tree[wday]; vert; vert=vert->down, y+=ys)
  343.         for (horz=vert; horz; horz=horz->next)
  344.             draw_bar(horz, horz->user ? horz->user->color : 0,
  345.                             x, y + c->week_bargap);
  346. }
  347.  
  348.  
  349. /*
  350.  * draw one entry bar.
  351.  */
  352.  
  353. static draw_bar(node, color, x, y)
  354.     struct weeknode        *node;        /* entry node to print */
  355.     int            color;        /* color, 0..7 */
  356.     int            x, y;        /* top left pos in canvas */
  357. {
  358.     register struct entry    *ep = node->entry;
  359.     register struct config    *c = &config;
  360.     Window            window = XtWindow(week.canvas);
  361.     int            xend;        /* right margin of chart */
  362.     int            w[2], b, e;    /* early/late, begin, end */
  363.     int            ee;        /* e with min length applied */
  364.     int            i;        /* warning counter, 0..1 */
  365.     int            slope;        /* delta-x of the arrowheads */
  366.     XPoint            point[7];    /* polygon vertex list */
  367. #ifdef JAPAN
  368.     int            ji, jdeltax, plen;
  369.     XChar2b            jstr[50];
  370.     strpack            partialstr[MAXPARTIALSTRING];
  371.     unsigned char        strpool[MAXPARTIALCHAR];
  372. #endif
  373.  
  374.     slope = c->week_barheight * SLOPE;
  375.     xend = x + c->week_hourwidth * (c->week_maxhour - c->week_minhour);
  376.     i = ep->early_warn > ep->late_warn;
  377.     w[!i] = TOD(ep->time) - ep->early_warn;
  378.     w[ i] = TOD(ep->time) - ep->late_warn;
  379.     b     = TOD(ep->time);
  380.     e     = TOD(ep->time) + (ep->notime ? 0 : ep->length);
  381.     w[0]  = x + XPOS(w[0]);
  382.     w[1]  = x + XPOS(w[1]);
  383.     b     = x + XPOS(b);
  384.     e     = x + XPOS(e);
  385.     ee    = e < b+MINLEN ? b+MINLEN : e;
  386.  
  387.     if (config.weekwarn && !ep->notime)
  388.         for (i=0; i < 2; i++)
  389.         if (w[i] < b && w[i] <= w[1] && b+slope > 0) {
  390.             point[5].x =
  391.             point[0].x =
  392.             point[2].x = BOUND(w[i]+slope, x, xend);
  393.             point[1].x = BOUND(w[i], x, xend);
  394.             point[3].x =
  395.             point[4].x = BOUND(b+slope, point[0].x, xend);
  396.             point[5].y =
  397.             point[0].y =
  398.             point[4].y = y;
  399.             point[1].y = y + c->week_barheight/2+1;
  400.             point[2].y =
  401.             point[3].y = y + (c->week_barheight&~1)+1;
  402.             set_color(COL_WWARN);
  403.             XFillPolygon(display, window, gc, point, 5,
  404.                         Convex, CoordModeOrigin);
  405.             set_color(COL_WFRAME);
  406.             XDrawLines(display, window, gc, point, 6,
  407.                             CoordModeOrigin);
  408.         }
  409.  
  410.     point[6].x =
  411.     point[0].x =
  412.     point[2].x = BOUND(b+slope, x, xend);
  413.     point[1].x = BOUND(b, x, xend-MINLEN);
  414.     point[3].x = BOUND(ee-slope, point[0].x, xend);
  415.     point[3].x =
  416.     point[5].x = BOUND(point[3].x, point[1].x+MINLEN, xend);
  417.     point[4].x = BOUND(e, point[3].x, xend);
  418.     point[6].y =
  419.     point[0].y =
  420.     point[5].y = y;
  421.     point[1].y =
  422.     point[4].y = y + c->week_barheight/2+1;
  423.     point[2].y =
  424.     point[3].y = y + (c->week_barheight&~1)+1;
  425.     if (ep->notime)
  426.         point[3].x = point[5].x = point[0].x;
  427.     set_color(ep->suspended ? COL_WWARN : COL_WUSER_0 + color);
  428.     XFillPolygon(display, window, gc, point, 6, Convex, CoordModeOrigin);
  429.     set_color(COL_WFRAME);
  430.     XDrawLines(display, window, gc, point, 7, CoordModeOrigin);
  431.  
  432.     if (*node->text) {
  433.         char buf[100];
  434.         strcpy(buf, node->text);
  435. #ifdef JAPAN
  436.         partialstr->strptr = strpool;
  437.         if ((plen = mixedstrlen_in_pixels(node->text, partialstr,
  438.                           FONT_WNOTE, FONT_JNOTE)) >
  439.                 xend - x) {
  440.             for (plen = ji = 0; partialstr[ji].strptr != NULL &&
  441.                         ji < MAXPARTIALSTRING; ji++) {
  442.                 if (plen + partialstr[ji].pixlen > xend - x) {
  443.                                 /* Truncating*/
  444.                     partialstr[ji].length *= (double)
  445.                             (xend-x-plen)/(double)
  446.                             partialstr[ji].pixlen;
  447.                     plen = xend - x;
  448.                     if (partialstr[ji].length == 0 ||
  449.                         partialstr[ji].asciistr == False &&
  450.                        (partialstr[ji].length &= ~1) == 0)
  451.                         partialstr[ji].strptr = NULL;
  452.                     break;
  453.                 } else
  454.                     plen += partialstr[ji].pixlen;
  455.             }
  456.         }
  457.           if (node->textinside) {
  458.             x = point[0].x;
  459.             x += (point[3].x-point[0].x - plen) / 2;
  460.             if (x + plen > xend-plen)
  461.                 x = xend-1 - plen;
  462.         } else
  463.             x = point[4].x + 3;
  464. #else
  465.         if (node->textinside) {
  466.             int l;
  467.             x = point[0].x;
  468.             truncate_string(buf, xend - x, FONT_WNOTE);
  469.             l = strlen_in_pixels(buf, FONT_WNOTE);
  470.             x += (point[3].x-point[0].x - l) / 2;
  471.             if (x + l > xend-1)
  472.                 x = xend-1 - l;
  473.         } else {
  474.             x = point[4].x + 3;
  475.             truncate_string(buf, xend - x, FONT_WNOTE);
  476.         }
  477. #endif
  478.         set_color(COL_WNOTE);
  479.         XSetFont(display, gc, font[FONT_WNOTE]->fid);
  480. #ifdef JAPAN
  481.         XSetFont(display, jgc, font[FONT_JNOTE]->fid);
  482.         for (ji = 0, jdeltax = x; partialstr[ji].strptr != NULL &&
  483.                         ji < MAXPARTIALSTRING; ji++) {
  484.             if (partialstr[ji].asciistr == True)
  485.                 XDrawString(display, window, gc,
  486.                     jdeltax, y + c->week_barheight/2 +
  487.                     font[FONT_WDAY]->max_bounds.ascent/2,
  488.                     partialstr[ji].strptr,
  489.                     partialstr[ji].length);
  490.             else
  491.                 XDrawString16(display, window, jgc,
  492.                     jdeltax, y + c->week_barheight/2 +
  493.                     font[FONT_WDAY]->max_bounds.ascent/2,
  494.                     (XChar2b *)partialstr[ji].strptr,
  495.                     partialstr[ji].length/2);
  496.             jdeltax += partialstr[ji].pixlen;
  497.         }
  498. #else
  499.         XDrawString(display, window, gc,
  500.             x, y + c->week_barheight/2
  501.                  + font[FONT_WDAY]->max_bounds.ascent/2,
  502.             buf, strlen(buf));
  503. #endif
  504.     }
  505. }
  506.